package top.wilsonlv.jaguar.webrtc.controller;

import com.alibaba.fastjson2.JSONObject;
import dev.onvoid.webrtc.*;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import top.wilsonlv.jaguar.web.response.JsonResult;
import top.wilsonlv.jaguar.webrtc.compnent.VideoStreamPeerConnectionObserver;

import javax.swing.*;
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * @author lvws
 * @since 2025/1/10
 */
@Slf4j
@RestController
@RequestMapping("/webrtc")
@Tag(name = "WebRTC")
@RequiredArgsConstructor
public class WebRTCController {

    private final PeerConnectionFactory factory = new PeerConnectionFactory();

    private final Set<RTCPeerConnection> peerConnections = new HashSet<>();


    @GetMapping(value = "/createOffer", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    @Operation(summary = "createOffer")
    public SseEmitter createOffer(@RequestParam String offer) throws IOException {
        SseEmitter sseEmitter = new SseEmitter(120000L);

        PeerConnectionObserver observer = new VideoStreamPeerConnectionObserver() {

            @Override
            public void onIceCandidate(RTCIceCandidate rtcIceCandidate) {
                log.info("onIceCandidate");

                Map<String, Object> data = new HashMap<>();
                data.put("type", "icecandidate");
                data.put("data", rtcIceCandidate);

                try {
                    sseEmitter.send(JsonResult.success(data));
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }

            @Override
            public void onIceConnectionChange(RTCIceConnectionState state) {
                log.info(state.toString());

                JFrame jFrame = this.getJFrame();

                switch (state) {
                    case CONNECTED -> jFrame.setVisible(true);
                    case DISCONNECTED -> {
                        jFrame.setVisible(false);
                        sseEmitter.complete();
                    }
                }
            }
        };

        RTCPeerConnection peerConnection = factory.createPeerConnection(new RTCConfiguration(), observer);

        JSONObject jsonObject = JSONObject.parseObject(offer);
        RTCSdpType type = RTCSdpType.valueOf(jsonObject.getString("type").toUpperCase());
        String sdp = jsonObject.getString("sdp");

        RTCSessionDescription rtcSessionDescription = new RTCSessionDescription(type, sdp);
        peerConnection.setRemoteDescription(rtcSessionDescription, new SetSessionDescriptionObserver() {
            @Override
            public void onSuccess() {
                log.info("setRemoteDescription  success");
            }

            @Override
            public void onFailure(String error) {
                log.error(error);
            }
        });

        peerConnection.createAnswer(new RTCAnswerOptions(), new CreateSessionDescriptionObserver() {

            @Override
            public void onSuccess(RTCSessionDescription description) {
                log.info("createAnswer success");
                peerConnection.setLocalDescription(description, new SetSessionDescriptionObserver() {
                    @Override
                    public void onSuccess() {
                        log.info("setLocalDescription  success");
                    }

                    @Override
                    public void onFailure(String error) {
                        log.error(error);
                    }
                });

                Map<String, Object> data = new HashMap<>();
                data.put("type", "answer");
                data.put("data", description);

                try {
                    sseEmitter.send(JsonResult.success(data));
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }

            @Override
            public void onFailure(String error) {
                log.error(error);
            }
        });

        sseEmitter.onTimeout(() -> {
            try {
                sseEmitter.send(JsonResult.fail("使用超时"));
            } catch (IOException e) {
                log.error(e.getMessage(), e);
            }

            sseEmitter.complete();
        });

        sseEmitter.onCompletion(() -> {
            peerConnections.remove(peerConnection);
        });

        peerConnections.add(peerConnection);
        return sseEmitter;
    }

    @PostMapping(value = "/onIceCandidate")
    @Operation(summary = "onIceCandidate")
    public JsonResult<Void> onIceCandidate(@RequestBody Map<String, Object> body) {
        for (RTCPeerConnection peerConnection : peerConnections) {
            String sdpMid = (String) body.get("sdpMid");
            int sdpMLineIndex = (int) body.get("sdpMLineIndex");
            String candidate = (String) body.get("candidate");

            RTCIceCandidate rtcIceCandidate = new RTCIceCandidate(sdpMid, sdpMLineIndex, candidate);
            peerConnection.addIceCandidate(rtcIceCandidate);
        }
        return JsonResult.success();
    }

}
